import { getSafeName, md5 } from "./utils";

/**
 * define type of any item in the store
 */
export interface StoreItem<T> {
	name: string;
	value: T;
}

/**
 * store for injected data
 */
export class Store {
	constructor(public name: string) {}

	items: StoreItem<any>[] = [];

	add(item: StoreItem<any>) {
		this.items.push(item);
	}

	exist(target: any) {
		const safeName = getSafeName(target);
		for (let i in this.items) {
			if (this.items[i].name === safeName) return true;
		}

		return false;
	}

	get(target: any, useHash: boolean = true) {
		const safeName = useHash ? getSafeName(target) : target;
		for (let i in this.items) {
			if (this.items[i].name === safeName) return this.items[i].value;
		}
		return null;
	}
}

/**
 * controller to manage all stores
 */
class StoreController {
	private stores: Store[] = [];

	is(item: Store) {
		return item instanceof Store;
	}

	add(item: Store) {
		this.stores.push(item);
	}

	create() {
		return createStore();
	}

	count() {
		return this.stores.length;
	}

	exist(storeOrName: Store | string | symbol) {
		const name =
			typeof storeOrName === "object" ? storeOrName.name : storeOrName;
		for (let i in this.stores) {
			if (this.stores[i].name === name) return true;
		}

		return false;
	}
}

export const storeController = new StoreController();

export const createStore = () => {
	const hashName = md5(
		`new Store()/atPosition/${storeController.count()}`
	);
	const store = new Store(hashName);
	storeController.add(store);
	return store;
};

export const rootStore = createStore();
